package com.briup.pai.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.briup.pai.common.constant.OperatorConstant;
import com.briup.pai.common.enums.OperatorCategoryEnum;
import com.briup.pai.common.enums.ResultCodeEnum;
import com.briup.pai.common.exception.BriupAssert;
import com.briup.pai.common.exception.CustomException;
import com.briup.pai.convert.OperatorConvert;
import com.briup.pai.dao.OperatorMapper;
import com.briup.pai.entity.dto.OperatorImportDTO;
import com.briup.pai.entity.dto.OperatorUpdateDTO;
import com.briup.pai.entity.po.Operator;
import com.briup.pai.entity.vo.DropDownVO;
import com.briup.pai.entity.vo.OperatorEchoVO;
import com.briup.pai.entity.vo.OperatorPageVO;
import com.briup.pai.entity.vo.PageVO;
import com.briup.pai.service.IOperatorService;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
//添加缓存前缀
@CacheConfig(cacheNames = OperatorConstant.OPERATOR_CACHE_PREFIX)
public class OperatorServiceImpl extends ServiceImpl<OperatorMapper, Operator> implements IOperatorService {

    @Autowired
    private OperatorConvert operatorConvert;
    @Override
    @CacheEvict(key = "T(com.briup.pai.common.constant.CommonConstant).DROPDOWN_CACHE_PREFIX")

    public void importOperator(MultipartFile file) {
        //判断文件类型
        BriupAssert.requireExcel(file);
        //过滤已存在的
        //查询已存在的
        List<String> existOperatorNames = new ArrayList<>(this.baseMapper.selectList(null)
                .stream().map(Operator::getOperatorName).toList());
        //读取excel文件内容，并做数据的转换
        //准备列表，数据库入库
        List<OperatorImportDTO> list = new ArrayList<>();
        try {
            EasyExcel.read(file.getInputStream(), OperatorImportDTO.class, new AnalysisEventListener<OperatorImportDTO>() {


                @Override
                public void invoke(OperatorImportDTO operatorImportDTO, AnalysisContext analysisContext) {
                    //执行一行时验证
                    if(!existOperatorNames.contains(operatorImportDTO.getOperatorName())){
                        //添加数据
                        list.add(operatorImportDTO);
                    }
                    existOperatorNames.add(operatorImportDTO.getOperatorName());

                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                    //执行完毕之后，筛选数据
                    //类型转换
                   List<Operator> operatorList = operatorConvert.operatorImportDto2PoList(list).stream()
                            .filter(s->s.getOperatorType()!=-1&&s.getOperatorCategory()!=-1).toList();
                    //获取当前外部类对象
                    IOperatorService operatorService = (IOperatorService) AopContext.currentProxy();
                    operatorService.saveBatch(operatorList);

                }
            }).sheet(0).doRead();

        } catch (IOException e) {
            throw new CustomException(ResultCodeEnum.FILE_IMPORT_ERROR);
        }
        System.out.println("导入算子数据成功！");

    }

    @Override
    public PageVO<OperatorPageVO> getOperatorByPageAndCondition(Long pageNum, Long pageSize, Integer operatorType, Integer operatorCategory) {
        // 定义分页
        IPage<Operator> page = new Page<>(pageNum, pageSize);
        // 查询
        LambdaQueryWrapper<Operator> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ObjectUtil.isNotNull(operatorType), Operator::getOperatorType, operatorType)
                .eq(ObjectUtil.isNotNull(operatorCategory), Operator::getOperatorCategory, operatorCategory);
        List<Operator> operators = this.baseMapper.selectList(page, lqw);
        List<OperatorPageVO> operatorPageVOS = operatorConvert.po2OperatorPageVOList(operators);
        PageVO<OperatorPageVO> result = new PageVO<>();
        result.setTotal(page.getTotal());
        result.setData(operatorPageVOS);
        return result;
    }

    @Override
    @Cacheable(key = "#operatorId", unless = "#result == null")
    public OperatorEchoVO getOperatorById(Integer operatorId) {
        //验证该id下算在是否存在
        Operator operator = BriupAssert.requireNotNull(this, Operator::getId, operatorId, ResultCodeEnum.DATA_NOT_EXIST);
        return operatorConvert.po2OperatorEchoVO(operator);
    }

    @Override
    @CachePut(key = "#dto.getOperatorId()", unless = "#result == null")
    public OperatorEchoVO modifyOperatorById(OperatorUpdateDTO dto) {
        //算子必须存在
        Operator operator = BriupAssert.requireNotNull(this, Operator::getId, dto.getOperatorId(), ResultCodeEnum.DATA_NOT_EXIST);
        //算子名称与路径不能重复
        BriupAssert.requireNull(this, Operator::getOperatorName, dto.getOperatorName(),
                Operator::getOperatorUrl, dto.getOperatorUrl(),ResultCodeEnum.DATA_ALREADY_EXIST);
        //类型转化
        operator = operatorConvert.operatorUpdateDTO2po(dto);
        this.updateById(operator);
      return operatorConvert.po2OperatorEchoVO(operator);
    }

    @Override
    @Caching(evict = {
            @CacheEvict(key = "#operatorId"),
            @CacheEvict(key = "T(com.briup.pai.common.constant.CommonConstant).DROPDOWN_CACHE_PREFIX")
    })
    public void removeOperatorById(Integer operatorId) {
        BriupAssert.requireNotNull(this, Operator::getId, operatorId, ResultCodeEnum.DATA_NOT_EXIST);
        this.removeById(operatorId);

    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional
    public void removeOperatorByIds(List<Integer> ids) {
        this.removeBatchByIds(ids);

    }

    @Override
    @Cacheable(key = "T(com.briup.pai.common.constant.CommonConstant).DROPDOWN_CACHE_PREFIX",
            unless = "#result == null || #result.isEmpty()")
    public Map<Integer, List<DropDownVO>> getOperatorDropDownList() {
        //准备map
        Map<Integer, List<DropDownVO>> map = new HashMap<>();
        //按照category遍历并且进行查询
        OperatorCategoryEnum.categoryList().forEach(categoryId->{
            LambdaQueryWrapper<Operator> lqw = new LambdaQueryWrapper<>();
            lqw.eq(Operator::getOperatorCategory, categoryId);
            List<Operator> list =this.list(lqw);
            List<DropDownVO> dropDownVOList = operatorConvert.po2DropDownList( list);
            map.put(categoryId, dropDownVOList);
        });
        return map;
    }
}